﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Collections.Concurrent;
using System.Security.Cryptography;
using RestNews.Data.Models;

namespace RestNews.Util.DigestAuthentication
{
    public class NonceProvider
    {
        private static ConcurrentDictionary<string, Tuple<int, DateTime>> nonces = new ConcurrentDictionary<string, Tuple<int, DateTime>>();
        private static object syncRoot = new object();
        /// <summary>
        /// Generates this instance.
        /// </summary>
        /// <returns></returns>
        public static string Generate(RestNewsContext db)
        {
            byte[] bytes = new byte[16];
            RandomNumberGenerator rng = RandomNumberGenerator.Create();
            rng.GetBytes(bytes);
            string nonce = bytes.ToMD5Hash();

            NonceStorage nonceData = new NonceStorage()
            {
                Nonce = nonce,
                NonceCount = 0,
                ExpirationDate = DateTime.Now.Add(TimeSpan.FromMinutes(10))
            };

            db.NonceStorages.Add(nonceData);
            db.SaveChanges();

            return nonce;
        }

        /// <summary>
        /// Determines whether the specified nonce is valid.
        /// </summary>
        /// <param name="nonce">The nonce.</param>
        /// <param name="nonceCount">The nonce count.</param>
        /// <returns>
        ///   <c>true</c> if the specified nonce is valid; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsValid(RestNewsContext db, string nonce, string nonceCount)
        {
            NonceStorage cachedNonce = db.NonceStorages.FirstOrDefault(n => n.Nonce == nonce);

            if (cachedNonce != null) // nonce is found
            {
                // nonce count is greater than the one in record
                if (Int32.Parse(nonceCount) > cachedNonce.NonceCount)
                {
                    // nonce has not expired yet
                    if (cachedNonce.ExpirationDate > DateTime.Now)
                    {
                        cachedNonce.ExpirationDate = DateTime.Now.Add(TimeSpan.FromMinutes(10));
                        cachedNonce.NonceCount++;
                        db.SaveChanges();
                        return true;
                    }
                }
            }

            return false;
        }
    }
}